{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 将序列分解为单独的变量\n",
    "- 不仅仅只是元组或列表，只要对象是可迭代的，就可以执行分解操作。 包括字符串，文件对象，迭代器和生成器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2020'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "date = ['2020', '08', '20']\n",
    "year, mon, day = date\n",
    "year"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 解压可迭代对象赋值给多个变量\n",
    "- 星号表达式：存储多个变量\n",
    "    - 也可以用在开头\n",
    "    - 专门为解压不确定个数或任意个数元素的可迭代对象而设计的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['773-555-1212', '847-555-1212']"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')\n",
    "name, email, *phone_numbers = record\n",
    "phone_numbers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/var/empty'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 用于字符串分割\n",
    "line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false'\n",
    "uname, *fields, homedir, sh = line.split(':')\n",
    "homedir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "15"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 甚至递归\n",
    "def sum(items):\n",
    "    head, *tail = items\n",
    "    return head + sum(tail) if tail else head\n",
    "items = [1, 2, 3, 4, 5]\n",
    "sum(items)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 保留最后 N 个元素\n",
    "- 队列 ：collections.deque\n",
    "- deque的方法：append; appendleft; pop; popleft; clear; copy; count; extend"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "deque([3, 4])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import deque\n",
    "l = deque(maxlen = 2)\n",
    "l.append(2)\n",
    "l.append(3)\n",
    "l.append(4)\n",
    "\n",
    "l"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 查找最大或最小的 N 个元素\n",
    "- 堆队列算法（优先队列算法）：heapq \n",
    "    - nlargest(n, num, key) 最大\n",
    "    - nsmallest(n, num, key) 最小\n",
    "    - n 值较小时性能最好。 对于更大的值，使用 sorted() 函数会更有效率\n",
    "    - min(); max()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([4, 3, 2], [-3, -2, -1])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import heapq\n",
    "nums =  [1, -1, 2, 0, -2, 3, -3, 4]\n",
    "heapq.nlargest(3, nums), heapq.nsmallest(3, nums)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  1.5 实现一个优先级队列\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1..6 字典中的键映射多个值\n",
    "- collections中的defaultdict\n",
    "- defaultdict 会自动为将要访问的键（就算目前字典中并不存在这样的键）创建映射实体\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(defaultdict(list, {'a': [1, 2]}), defaultdict(set, {'a': {1, 2}}), {})"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import defaultdict\n",
    "l = defaultdict(list)\n",
    "l['a'].append(1)\n",
    "l['a'].append(2)\n",
    "\n",
    "s = defaultdict(set)\n",
    "s['a'].add(1)\n",
    "s['a'].add(2)\n",
    "\n",
    "d = {}\n",
    "# d['a'].add(1) 键不存在，会报错: 不会自动创建实体\n",
    "l, s, d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.7字典排序\n",
    "\n",
    "- collections.OrderedDict\n",
    "    - 控制字典中元素的顺序 move_to_end()\n",
    "    - OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候， 它会被放到链表的尾部\n",
    "    - 大小是一个普通字典的两倍"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(OrderedDict([('bar', 2), ('spam', 3), ('foo', 1)]), None)"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import OrderedDict\n",
    "d = OrderedDict()\n",
    "d['foo'], d['bar'], d['spam'] = 1, 2, 3\n",
    "\n",
    "d.move_to_end('foo') # 移动 dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.8 字典的运算\n",
    "- 求最小值、最大值、排序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('IBM', 612.78)"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prices = {\n",
    "    'ACME': 45.23,\n",
    "    'AAPL': 612.78,\n",
    "    'IBM': 205.55,\n",
    "    'HPQ': 37.20,\n",
    "    'FB': 10.75\n",
    "}\n",
    "\n",
    "max(prices), max(prices.values())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AAPL\n"
     ]
    }
   ],
   "source": [
    "num = max(prices.values())\n",
    "for k, v in prices.items():\n",
    "    if v == num:\n",
    "        print(k)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'AAPL'"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# key->value->max(value):key\n",
    "max(prices, key = lambda k: prices[k])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "205.55"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = lambda k: prices[k]\n",
    "a('IBM')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.9 查找两字典的相同点\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "({'x', 'y'}, {'z'}, {('y', 2)})"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = {\n",
    "    'x' : 1,\n",
    "    'y' : 2,\n",
    "    'z' : 3\n",
    "}\n",
    "\n",
    "b = {\n",
    "    'w' : 10,\n",
    "    'x' : 11,\n",
    "    'y' : 2\n",
    "}\n",
    "a.keys() & b.keys(), a.keys() - b.keys(), a.items() & b.items()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.10 删除序列相同元素并保持顺序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1, 2, 5, 9, 10}"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 5, 2, 1, 9, 1, 5, 10] # hashable\n",
    "set(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}]\n",
    "# set(d) TypeError: unhashable type: 'dict'\n",
    "# 只能遍历判断删除了"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.11 命名切片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([1, 2, 3], [1, 2, 3], slice(1, 4, 1))"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "items = [0, 1, 2, 3, 4, 5, 6]\n",
    "a = slice(1, 4, 1)\n",
    "items[1:4], items[a], a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 4, 1)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.start, a.stop, a.step"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.12 序列中出现次数最多的元素\n",
    "- collections.Counter类为此设计；\n",
    "- most_common()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('eyes', 8), ('the', 5), ('look', 4)]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import Counter\n",
    "\n",
    "words = [\n",
    "    'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',\n",
    "    'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',\n",
    "    'eyes', \"don't\", 'look', 'around', 'the', 'eyes', 'look', 'into',\n",
    "    'my', 'eyes', \"you're\", 'under'\n",
    "]\n",
    "\n",
    "word_counts = Counter(words)\n",
    "# 出现频率最高的3个单词\n",
    "word_counts.most_common(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Counter({'look': 4,\n",
       "          'into': 3,\n",
       "          'my': 3,\n",
       "          'eyes': 8,\n",
       "          'the': 5,\n",
       "          'not': 1,\n",
       "          'around': 2,\n",
       "          \"don't\": 1,\n",
       "          \"you're\": 1,\n",
       "          'under': 1}),\n",
       " Counter({'why': 1,\n",
       "          'are': 1,\n",
       "          'you': 1,\n",
       "          'not': 1,\n",
       "          'looking': 1,\n",
       "          'in': 1,\n",
       "          'my': 1,\n",
       "          'eyes': 1}),\n",
       " Counter({'look': 4,\n",
       "          'into': 3,\n",
       "          'my': 4,\n",
       "          'eyes': 9,\n",
       "          'the': 5,\n",
       "          'not': 2,\n",
       "          'around': 2,\n",
       "          \"don't\": 1,\n",
       "          \"you're\": 1,\n",
       "          'under': 1,\n",
       "          'why': 1,\n",
       "          'are': 1,\n",
       "          'you': 1,\n",
       "          'looking': 1,\n",
       "          'in': 1}))"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "morewords = ['why','are','you','not','looking','in','my','eyes']\n",
    "a = Counter(words)\n",
    "b = Counter(morewords)\n",
    "a, b, a+b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.13 通过某个关键字排序一个字典列表\n",
    "- operator.itemgetter \n",
    "    - 函数也支持多个 keys\n",
    "    - Return a callable object / callable表示“可调用”\n",
    "    - itemgetter() 有时候也可以用 lambda 表达式代替"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},\n",
       " {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},\n",
       " {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},\n",
       " {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "rows = [\n",
    "    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},\n",
    "    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},\n",
    "    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},\n",
    "    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}\n",
    "]\n",
    "# Return a callable object\n",
    "rows_by_fname = sorted(rows, key=itemgetter('fname')) \n",
    "\n",
    "\n",
    "rows_by_fname\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.14 排序不支持原生比较的对象\n",
    "- 创建实例类，可以对类的对象进行排序\n",
    "- operator.attrgetter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[User(23), User(3), User(99)]\n",
      "[User(3), User(23), User(99)]\n",
      "[User(3), User(23), User(99)]\n"
     ]
    }
   ],
   "source": [
    "class User:\n",
    "    def __init__(self, user_id):\n",
    "        self.user_id = user_id\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'User({})'.format(self.user_id)\n",
    "\n",
    "from operator import attrgetter\n",
    "\n",
    "def sort_notcompare():\n",
    "    users = [User(23), User(3), User(99)]\n",
    "    print(users)\n",
    "    print(sorted(users, key=lambda u: u.user_id))\n",
    "    print(sorted(users, key=attrgetter('user_id')))\n",
    "sort_notcompare()    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.15 通过某个字段将记录分组\n",
    "- 你有一个字典或者实例的序列，然后你想根据某个特定的字段比如 date 来分组迭代访问\n",
    "- itertools.groupby()\n",
    "-  groupby() 仅仅检查连续的元素，如果事先并没有排序完成的话，分组函数将得不到想要的结果。\n",
    "- 将字段入字典；再以此遍历输出 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "rows = [\n",
    "    {'address': '5412 N CLARK', 'date': '07/01/2012'},\n",
    "    {'address': '5148 N CLARK', 'date': '07/04/2012'},\n",
    "    {'address': '5800 E 58TH', 'date': '07/02/2012'},\n",
    "    {'address': '2122 N CLARK', 'date': '07/03/2012'},\n",
    "    {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},\n",
    "    {'address': '1060 W ADDISON', 'date': '07/02/2012'},\n",
    "    {'address': '4801 N BROADWAY', 'date': '07/01/2012'},\n",
    "    {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "07/01/2012\n",
      "  {'address': '5412 N CLARK', 'date': '07/01/2012'}\n",
      "  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}\n",
      "07/02/2012\n",
      "  {'address': '5800 E 58TH', 'date': '07/02/2012'}\n",
      "  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}\n",
      "  {'address': '1060 W ADDISON', 'date': '07/02/2012'}\n",
      "07/03/2012\n",
      "  {'address': '2122 N CLARK', 'date': '07/03/2012'}\n",
      "07/04/2012\n",
      "  {'address': '5148 N CLARK', 'date': '07/04/2012'}\n",
      "  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}\n"
     ]
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "from itertools import groupby\n",
    "\n",
    "# Sort by the desired field first\n",
    "rows.sort(key=itemgetter('date'))\n",
    "# Iterate in groups\n",
    "for date, items in groupby(rows, key=itemgetter('date')):\n",
    "    print(date)\n",
    "    for i in items:\n",
    "        print(' ', i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.16 过滤序列元素\n",
    "- filter\n",
    "- itertools.compress"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 10, 2, 3]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mylist = [1, 4, -5, 10, -7, 2, 3, -1]\n",
    "[n for n in mylist if n > 0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.17 从字典中提取子集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'AAPL': 612.78, 'IBM': 205.55}"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prices = {\n",
    "    'ACME': 45.23,\n",
    "    'AAPL': 612.78,\n",
    "    'IBM': 205.55,\n",
    "    'HPQ': 37.20,\n",
    "    'FB': 10.75\n",
    "}\n",
    "\n",
    "\n",
    "{k:v for k,v in prices.items() if v > 200}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.18 映射名称到序列元素\n",
    "- collections.namedtuple\n",
    "- 实例化和类实例相似， 但支持元组操作\n",
    "- 值不可更改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Subscriber(addr='jonesy@example.com', joined='2012-10-19'),\n",
       " 'jonesy@example.com',\n",
       " '2012-10-19')"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import namedtuple\n",
    "\n",
    "Subscriber = namedtuple('Subscriber', ['addr', 'joined'])\n",
    "sub = Subscriber('jonesy@example.com', '2012-10-19')\n",
    "sub, sub.addr, sub.joined\n",
    "# sub.addr = 'hang@exaple.com' AttributeError: can't set attribute"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### 1.19 转换并同时计算数据\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "55"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nums = [1, 2, 3, 4, 5]\n",
    "\n",
    "sum(x * x for x in nums) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.20 合并多个字典或映射"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 2, 3)"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = {'x': 1, 'z': 3 }\n",
    "b = {'y': 2, 'z': 4 }\n",
    "from collections import ChainMap\n",
    "c = ChainMap(a,b)\n",
    "c['x'], c['y'], c['z']\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
